﻿using System;
using System.Data.Common;
using System.Linq;

using Centido.Core;

namespace Centido.Management.ConsoleManager
{
    /// <summary>
    ///   A console command that lists child units of the specified unit or lists child units of all units.
    /// </summary>
    internal class ListUnitChildrenCommand : Command
    {
        /// <summary>
        ///   The unit name parameter.
        /// </summary>
        public const string UnitNameParameter = "unit";

        /// <summary>
        ///   The unit name parameter (short name).
        /// </summary>
        public const string UnitNameShortParameter = "u";

        /// <summary>
        ///   The display all option parameter.
        /// </summary>
        public const string DisplayAllOptionParameter = "all";

        /// <summary>
        ///   The display all option parameter (short name).
        /// </summary>
        public const string DisplayAllOptionShortParameter = "i";


        /// <summary>
        ///   Gets the console command name.
        /// </summary>
        public override string Name
        {
            get { return "listunitchildren"; }
        }

        /// <summary>
        ///   Gets the console command description.
        /// </summary>
        public override string Description
        {
            get { return Messages.ListUnitChildrenCommandDescription; }
        }

        
        /// <summary>
        ///   Gets the console command full description.
        /// </summary>
        public override string FullDescription
        {
            get { return Messages.ListUnitChildrenCommandFullDescription; }
        }


        /// <summary>
        ///   Executes the console command.
        /// </summary>
        /// <param name="context">The console command execution context.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="context"/> is null.</exception>
        public override void Execute(CommandExecutionContext context)
        {
            base.Execute(context);

            var domain = context.CurrentDomain;

            if (domain == null) return;

            try
            {
                // If the unit name was specified
                if (context.ParameterValueIsNotEmpty(UnitNameParameter, UnitNameShortParameter))
                {
                    // The unit name
                    var unitName = context.GetParameterValue(UnitNameParameter, UnitNameShortParameter);

                    // Trying to find the unit
                    var unit = domain.GetUnit(unitName);

                    // If the unit was not found
                    if (unit == null)
                    {
                        Console.WriteLine(Messages.CannotFindUnitError, unitName);
                        return;
                    }

                    DisplayUnitChildren(context, unit);
                }
                // If the unit was not specified
                else
                {
                    // Enumerating units
                    foreach (var unit in domain.Units.OrderBy(u => u.Name ?? string.Empty))
                    {
                        // If the all option was specified
                        if (context.GetParameterByName(DisplayAllOptionParameter, DisplayAllOptionShortParameter) != null
                            // ... and the unit has the display name
                            && !string.IsNullOrEmpty(unit.DisplayName))
                            Console.WriteLine("{0} ({1})", unit.Name, unit.DisplayName);
                        else
                            Console.WriteLine(unit.Name);

                        DisplayUnitChildren(context, unit, displayOffset: true);

                        Console.WriteLine();
                    }
                }
            }
            catch (DbException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine();
            }
        }


        /// <summary>
        ///   Displays unit children.
        /// </summary>
        /// <param name="context">The command execution context.</param>
        /// <param name="unit">The business unit.</param>
        /// <param name="displayOffset">The need to display the offset.</param>
        private static void DisplayUnitChildren(CommandExecutionContext context,
            Unit unit, bool displayOffset = false)
        {
            // Enumerating unit children
            foreach (var childUnit in unit.ChildUnits.OrderBy(u => u.Name))
            {
                // If the all option was specified
                if (context.GetParameterByName(DisplayAllOptionParameter, DisplayAllOptionShortParameter) != null
                    // ... and the child unit has the display name
                    && !string.IsNullOrEmpty(childUnit.DisplayName))
                    Console.WriteLine("{0}{1} ({2})",
                        displayOffset ? "     " : string.Empty,
                        childUnit.Name,
                        childUnit.DisplayName);
                else
                    Console.WriteLine("{0}{1}",
                        displayOffset ? "     " : string.Empty,
                        childUnit.Name);
            }
        }
    }
}
